const PINDDING = 'pindding'
const RESOLVE = 'resolved'
const REJECT = 'rejected'

// 处理链式调用的返回值
const newThen = (res, _newpromise, reslove, reject) => {
  // 当返回值是本身，没有意义继续使用 then 方法
  if (res === _newpromise) {
    throw new Error('can not return oneself')
  }
  // 判断返回的数据是否是 promise 对象（null 用 typeof 返回的也是 object ），或者函数
  if ((typeof res === 'object' && res !== null) || typeof res === 'function') {
    const then = res.then
    try {
      // 判断内部是否有 then 方法，并且是否是一个函数
      if (typeof then === 'function') {
        // 自调用 then 方法，并且 改变 this 指向
        then.call(res, r => {
          newThen(r, _newpromise, reslove, reject)
        }, e => {
          reject(e)
        })
      } else {
        // 没有 then 方法，或者 then 不是一个函数
        reslove(res)
      }
    } catch (error) {
      reject(error)
    }
  } else {
    // 是简单数据类型，直接抛出
    reslove(res)
  }
}

class _Promise {
  // 设置初始状态，实现只改变一次状态
  status = PINDDING
  result = undefined
  reason = undefined
  // 异步抛出数据时进行捕获
  resolveArr = []
  rejectArr = []

  constructor (func) {
    // 成功的回调
    const resolve = (result) => {
      if (this.status === 'pindding') {
        this.result = result
        this.status = RESOLVE
        this.resolveArr.map(func => func())
      }
    }
    // 失败的回调
    const reject = (reason) => {
      if (this.status === 'pindding') {
        this.result = reason
        this.status = REJECT
        this.resolveArr.map(func => func())
      }
    }
    try {
      // 自调用
      func(resolve, reject)
    } catch (error) {
      reject(error)
    }
  }

  then (resolve, reject) {
    // 判断两个参数是否为函数， 防止运行出错
    resolve = typeof resolve === 'function' ? resolve : (data) => data
    reject = typeof reject === 'function' ? reject : (err) => {
      throw new Error(err)
    }
    // 链式调用，返回 promise 对象
    const _newpromise = new _Promise((reslove, reject) => {
      // 抛出的成功函数
      if (this.status === RESOLVE) {
        setTimeout(() => {
          try {
            const res = resolve(this.result)
            newThen(res, _newpromise, reslove, reject)
          } catch (error) {
            reject(error)
          }
        })
      }
      // 抛出的失败函数
      if (this.status === REJECT) {
        setTimeout(() => {
          try {
            const res = reject(this.result)
            newThen(res, _newpromise, reslove, reject)
          } catch (error) {
            reject(error)
          }
        })
      }
      // 可能会异步调用 resolve 和 reject
      if (this.status === PINDDING) {
        this.resolveArr.push(() => {
          try {
            const res = resolve(this.result)
            newThen(res, _newpromise, reslove, reject)
          } catch (error) {
            reject(error)
          }
        })
        this.rejectArr.push(() => {
          try {
            const res = reject(this.result)
            newThen(res, _newpromise, reslove, reject)
          } catch (error) {
            reject(error)
          }
        })
      }
    })
    return _newpromise
  }

  catch (reject) {
    return this.then(undefined, reject)
  }

  all (arr) {
    return new _Promise((resolve, reject) => {
      const PromiseArr = Array.from(arr)
      const arr1 = []
      let count = 0
      const length = PromiseArr.length
      for (let i = 0; i < length; i++) {
        _Promise.reslove(PromiseArr[i]).then(res => {
          arr1.push(res)
          ++count === length && resolve(arr1)
        }).catch((err) => {
          reject(err)
        })
      }
    })
  }
}

module.exports = _Promise
